# -*- coding: utf-8 -*-

import logging
from functools import wraps
from typing import Union, Optional, Callable

from dtcloud import http
from dtcloud.http import request

from commons.core import CRUDBase

_logger = logging.getLogger(__name__)


def set_action(action: str):
    """装饰器函数，用于设置方法的动作属性"""

    def decorator(func: Callable):
        @wraps(func)
        def wrapper(*args, **kwargs):
            return func(*args, **kwargs)

        wrapper._action = action  # 设置动作属性
        return wrapper

    return decorator


class RestController(http.Controller, CRUDBase):
    """
        api路由生成规则
        create、 list: _prefix/_model.replace('.', '_')
        update、destroy、retrieve:  _prefix/_model.replace('.', '_')/<int:req_id>
    """
    _model: Optional[str] = None  # 指定模型
    _method_map = {
        'list': 'GET',  # 列表
        'create': 'POST',  # 创建
        'update': 'PUT',  # 更新
        'destroy': 'DELETE',  # 删除
        'retrieve': 'GET'  # 详情
    }
    _prefix = "/api"  # 路由前缀
    _default_auth = 'user'  # 默认权限,支持user、public、none、token
    _type = 'http'  # 支持http、jsonify
    _kwargs = {}
    _module: Optional[str] = None  # 指定模块名, 用于区分不同模块的接口
    _log_type: Optional[str] = None  # 指定日志类型：login、operate、parameter
    _group = None  # 操作模块

    @classmethod
    def __init_subclass__(cls, **kwargs):
        if ("RestController" in globals()
                and RestController in cls.__bases__
                and http.Controller not in cls.__bases__
        ):
            assert cls._model is not None, "必须指定`_model`模型值!!"
            assert cls._prefix.startswith('/'), "路由接口必须以`/`开头!!"
            assert cls._type in http._dispatchers, "请求类型不存在!!"

            path = cls.__module__.split('.')
            module = next(iter(path[2:]), '') if path[:2] == ['dtcloud', 'addons'] else ''
            http.Controller.children_classes[module].append(cls.as_view())

    @classmethod
    def as_view(cls):
        def _get_route(method):
            if cls._module:
                base_route = f"{cls._prefix}/{cls._module}/{cls._model.replace('.', '_')}"
            else:
                base_route = f"{cls._prefix}/{cls._model.replace('.', '_')}"
            return f"{base_route}/<int:req_id>" if method in ('update', 'destroy', 'retrieve') else base_route

        def _get_kwargs(method_func, request_method):
            kwargs = {'type': cls._type, 'description': getattr(method_func, '_action', '')}
            if request_method.upper() in ['POST', 'PUT']:
                if cls._type == 'http':
                    kwargs['csrf'] = False
                else:
                    kwargs['jsonp'] = True
            kwargs.update(cls._kwargs)
            # 添加日志类型
            if cls._log_type:
                kwargs['log'] = cls._log_type
            # 添加操作模块
            if cls._group:
                kwargs['group'] = cls._group
            return kwargs

        routes = {
            method: http.route(
                _get_route(method),
                auth=cls._default_auth,
                methods=[request_method.upper()],
                **_get_kwargs(getattr(cls, method), request_method)
            )(getattr(cls, method))
            for method, request_method in cls._method_map.items()
            if hasattr(cls, method) and not hasattr(getattr(cls, method), "original_routing")
        }

        return type(cls.__name__, (cls,), routes)

    def make_response(self, data, /, *, status=0, code=0, msg='success'):
        if isinstance(data, http.Response):
            return data

        return request.make_json_response({
            "status": status,
            "code": code,
            "data": data,
            "msg": msg
        })

    def create(self, **data):
        res = self.home_public_create_dict(data)
        return self.make_response(res if res else None)

    def update(self, req_id, **data):
        data['id'] = req_id
        res = self.home_public_write_dict(data)
        return self.make_response(res)

    def list(self, **query_params):
        res, count = self.home_public_list(**query_params)
        return self.make_response({
            "total": count,
            "items": res
        })

    def destroy(self, req_id: Union[int, list]) -> bool:
        """
        真删除
        """
        return self.make_response(
            self.home_public_delete(req_id)
        )

    def retrieve(self, req_id: int):
        res = self.home_public_read_one(req_id, None)
        return self.make_response(res)
